<template>
  <div
    ref="dom"
    v-click-outside="handleClickOutSide"
    class="c-dropdown g-jc-sb"
    :class="{ _disabled: disabled, _splitButton: splitButton && !disabled }"
  >
    <div class="c-dropdown-item g-flex-1" v-on="handle()">
      <slot />
    </div>
    <div class="c-dropdown-item g-flex-0" v-on="handleDrop()">
      <slot name="drop-icon">
        <img class="c-drop-icon" src="statics/header/icontriangle.svg" />
      </slot>
    </div>
  </div>
  <Teleport to="body">
    <!-- @mouseup.stop 是为了不触发clickoutside -->
    <div
      v-if="dropdownModel.isOpen"
      ref="dropItemDom"
      :class="'c-dropdown-menu ' + popperClass"
      :style="menuStyle"
      @mouseup.stop
    >
      <slot name="dropdown" />
    </div>
  </Teleport>
</template>

<script lang="ts" setup>
import { DropdownModel, AbsPosition, DivDom } from './DropdownModel';
import { onBeforeUnmount, onMounted, reactive, ref, computed, provide, watch } from 'vue';
import { ClickOutside as vClickOutside } from 'element-plus';

const props = withDefaults(
  defineProps<{
    // 是否分离label和下拉菜单,true则button是点击事件,下拉菜单内点击为command事件
    splitButton?: boolean,
    disabled?: boolean,
    // 下拉菜单显示的位置
    placement?: AbsPosition,
    // 下拉菜单触发方式
    trigger?: "click" | "hover" | "contextmenu",
    // 下拉菜单最大高度
    maxHeight?: number,
    tabindex?: number,
    popperClass?: string
  }>(),
  {
    splitButton: false,
    disabled: false,
    placement: 'bottom',
    trigger: 'click',
    maxHeight: 100,
    tabindex: 0,
    popperClass: ''
  }
);

const emit = defineEmits<{
  (e: 'click', data: any): void,
  (e: 'command', data: any): void,
  (e:'visible-change', visible:boolean):void,
}>();

const dom = ref<DivDom>(undefined);

const dropItemDom = ref<DivDom>(undefined);

const dropdownModel = reactive(new DropdownModel());

provide('dropdownModel', dropdownModel);

const menuStyle = computed(() => {
  return Object.assign(
    {
      zIndex: 2000,
      maxHeight: (props.maxHeight || 300) + 'px',
      minWidth: dropdownModel.width + 'px'
    },
    dropdownModel.getAbsPosition(props.placement, dropItemDom.value)
  );
});

watch(() => dropdownModel.isOpen, (val:boolean) => {
  emit('visible-change', val);
});

function handle() {
  if (props.disabled) return {};
  if (props.splitButton) return {
    click() {
      emit('command', '');
    }
  };
  
  return handleDrop();
}

function handleDrop() {
  if (props.disabled) return {};
  if (['hover'].includes(props.trigger)) return {
    mouseenter() {
      dropdownModel.open();
    },
    mouseleave() {
      dropdownModel.close();
    }
  };
  return {
    [props.trigger]() {
      dropdownModel.toggelOpen();
    },
  };
}

function handleCommand(item: any) {
  emit('command', item);
  dropdownModel.destroy();
}

provide('handleCommand', handleCommand);

function handleClickOutSide() {
  dropdownModel.close();
}

onMounted(() => {
  setTimeout(() => {
    dropdownModel.dom = dom.value;
  }, 10);
});

onBeforeUnmount(() => {
  dropdownModel.destroy();
});

</script>

<style lang="scss">
.c-dropdown {
  width: 100%;
  height: 100%;
  .c-dropdown-item{
    height: 100%;
  }
  ._disabled {
    cursor: not-allowed;
    color: #c1c5cb;
    filter: grayscale(100);
  }
  .c-drop-icon {
    margin-left: 2px;
  }
  & > * {
    height: 100%;
    display: inline-flex;
    align-items: center;
  }
  &._splitButton > * {
    &:hover {
      background-color: #d0d0d0;
      padding: 0px;
    }
  }
}
.c-dropdown-menu {
  position: absolute;
  overflow: auto;
  border: 1px solid #c2d1da;
  border-radius: 2px;
  padding: 3px 0;
  background-color: white;
}
</style>